package com.example.archivemanagement.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.archivemanagement.entity.Archive;
import com.example.archivemanagement.mapper.ArchiveMapper;
import com.example.archivemanagement.service.ArchiveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;

@Service
public class ArchiveServiceImpl extends ServiceImpl<ArchiveMapper, Archive> implements ArchiveService {

    @Value("${file.upload-dir}")
    private String uploadDir;

    @Override
    @Transactional
    public Archive uploadArchive(MultipartFile file, Archive archive) {
        try {
            String fileName = StringUtils.cleanPath(file.getOriginalFilename());
            String fileExtension = fileName.substring(fileName.lastIndexOf("."));
            String newFileName = UUID.randomUUID().toString() + fileExtension;
            
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }

            Path filePath = uploadPath.resolve(newFileName);
            Files.copy(file.getInputStream(), filePath);

            archive.setFilePath(filePath.toString());
            archive.setFileType(fileExtension.substring(1).toUpperCase());
            archive.setFileSize(formatFileSize(file.getSize()));
            
            save(archive);
            return archive;
        } catch (IOException e) {
            throw new RuntimeException("Failed to store file", e);
        }
    }

    @Override
    public Page<Archive> getRecentArchives(int page, int size) {
        Page<Archive> pageable = new Page<>(page, size);
        return page(pageable, new QueryWrapper<Archive>().orderByDesc("create_time"));
    }

    @Override
    public Page<Archive> searchArchives(String keyword, String category, String securityLevel, int page, int size) {
        QueryWrapper<Archive> queryWrapper = new QueryWrapper<>();
        
        if (StringUtils.hasText(keyword)) {
            queryWrapper.like("name", keyword)
                    .or()
                    .like("archive_number", keyword)
                    .or()
                    .like("description", keyword);
        }
        
        if (StringUtils.hasText(category)) {
            queryWrapper.eq("category", category);
        }
        
        if (StringUtils.hasText(securityLevel)) {
            queryWrapper.eq("security_level", securityLevel);
        }
        
        queryWrapper.orderByDesc("create_time");
        
        return page(new Page<>(page, size), queryWrapper);
    }

    @Override
    @Transactional
    public void deleteArchive(Long id) {
        Archive archive = getById(id);
        if (archive != null) {
            try {
                Files.deleteIfExists(Paths.get(archive.getFilePath()));
            } catch (IOException e) {
                throw new RuntimeException("Failed to delete file", e);
            }
            removeById(id);
        }
    }

    @Override
    @Transactional
    public Archive updateArchive(Archive archive) {
        updateById(archive);
        return archive;
    }

    @Override
    public List<Archive> getArchivesByCategory(String category) {
        return list(new QueryWrapper<Archive>().eq("category", category));
    }

    @Override
    public List<Archive> getArchivesBySecurityLevel(String securityLevel) {
        return list(new QueryWrapper<Archive>().eq("security_level", securityLevel));
    }

    private String formatFileSize(long size) {
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
        }
    }
} 